home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_3 / psm / source / main.c < prev    next >
C/C++ Source or Header  |  1993-07-28  |  36KB  |  1,172 lines

  1.  
  2. #include "psm.h"
  3.  
  4. struct List ScreenModeList;
  5.  
  6. /**
  7.  ** Definition of main window
  8.  **/
  9.  
  10. enum {
  11.     WINTAGS_ID = 1,
  12.  
  13.     PUBLIST_ID,
  14.     
  15.     OWNER_ID,
  16.     
  17.     CLOSE_ID,
  18.     JUMPTO_ID,
  19.     EXAMINE_ID,
  20.  
  21.     MAKEDEF_ID,
  22.     DEFAULT_ID,
  23.     DUPSCRN_ID,
  24.     MODSCRN_ID,
  25.     
  26.     SHANGHAI_ID,
  27.     AUTOPOP_ID,
  28.     NEWSCRN_ID,
  29.     QUIT_ID,
  30.     
  31.     ABOUT_ID,
  32. };
  33.  
  34. #define CURSCRN_GID GO_GRPID_A      // Gadget group that needs a public screen
  35.                                     // to be selected.
  36.  
  37. /**
  38.  ** Almost a menu strip for the main window
  39.  **/
  40.  
  41. struct NewMenu mainmenu[] = {
  42. { NM_TITLE, "Project",    0 , 0, 0, 0 },
  43.     {  NM_ITEM, "About...",   "A", 0, 0, (void *)ABOUT_ID },
  44.     {  NM_ITEM, "Quit",       "Q", 0, 0, (void *)QUIT_ID },
  45.  
  46.     {   NM_END, NULL,          0 , 0, 0, 0 },
  47. };
  48.  
  49. static ULONG __saveds __interrupt
  50. main_handler(struct GadOutline *go, ULONG command, struct GOIMsg *msg);
  51.  
  52. static ULONG main_outline[] = {
  53.  
  54. GO_OUTLINETAGS(0,0),
  55.     TAG_END,
  56.     GOA_BaseName,           (ULONG)&__BaseName[0],
  57.     GOA_SetUserHandler,     (ULONG)&main_handler,
  58.     GOA_SetTransHookData,   NULL,
  59.     GOA_UserIDCMP,          ~0,
  60.     GOA_ErrorReportLevel,     
  61.           (1L<<GOTYPE_FINE)  | (1L<<GOTYPE_FINE2)
  62.         | (1L<<GOTYPE_NOTE)  | (1L<<GOTYPE_NOTE2)
  63.         | (1L<<GOTYPE_WARN)  | (1L<<GOTYPE_WARN2)
  64.         | (1L<<GOTYPE_ALERT) | (1L<<GOTYPE_ALERT2) | (1L<<GOTYPE_ALERT3)
  65.         | (1L<<GOTYPE_FAIL)  | (1L<<GOTYPE_FAIL2)  | (1L<<GOTYPE_FAIL3),
  66.     GOA_AllocMenus,         (ULONG)&mainmenu[0],
  67.     TAG_END,
  68.  
  69. GO_WINDOWTAGS(0,WINTAGS_ID),
  70.     TAG_END,
  71.     WA_Title,           (ULONG)&__ShortTitle[0],
  72.     WA_ScreenTitle,     (ULONG)&__LongTitle[0],
  73.     WA_PubScreenFallBack, TRUE,
  74.     WA_IDCMP,           IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW |
  75.                         IDCMP_INTUITICKS | IDCMP_MENUPICK,
  76.     WA_Activate,        TRUE,
  77.     WA_CloseGadget,     TRUE,
  78.     WA_DepthGadget,     TRUE,
  79.     WA_DragBar,         TRUE,
  80.     WA_SizeGadget,      TRUE,
  81.     WA_SizeBBottom,     TRUE,
  82.     WA_SimpleRefresh,   TRUE,
  83.     WA_BackFill,        NULL,
  84.     TAG_END,
  85.  
  86. GO_COMMANDTAGS(0,0),
  87.     TAG_END,
  88.     GOCT_SetHotKey, 0,
  89.     TAG_END,
  90.  
  91. GO_VERTGRP(0,0,1),
  92. GOCT_SizeSpaceAbove, GO_TSIZE(GOM_PadSet,50,GOT_PercCharH),
  93. GOCT_SizeSpaceBelow, GO_TSIZE(GOM_PadSet,50,GOT_PercCharH),
  94. GOCT_SizeSpaceLeft, GO_TSIZE(GOM_PadSet,50,GOT_PercCharW),
  95. GOCT_SizeSpaceRight, GO_TSIZE(GOM_PadSet,50,GOT_PercCharW),
  96. TAG_END,
  97.  
  98.     GO_VDRAWGRP(0,0,1),
  99.     GOCT_SizeSpaceAbove, GO_TSIZE(GOM_PadSet,50,GOT_PercCharH),
  100.     GOCT_SizeSpaceBelow, GO_TSIZE(GOM_PadSet,50,GOT_PercCharH),
  101.     GOCT_SizeSpaceLeft, GO_TSIZE(GOM_PadSet,50,GOT_PercCharW),
  102.     GOCT_SizeSpaceRight, GO_TSIZE(GOM_PadSet,50,GOT_PercCharW),
  103.     TAG_END,
  104.     GODT_DrawStdFrame, GO_SCLPNT(SHINEPEN,0,0,63,63),
  105.     TAG_END,
  106.  
  107.         GO_GTBOX(LISTVIEW_KIND, 0, PUBLIST_ID, 1,
  108.             (ULONG)&"_Public Screens", PLACETEXT_ABOVE|NG_HIGHLABEL),
  109.         GOCT_SizeBodyHeight, GO_TSIZE(GOM_StdMax,500,GOT_PercCharH),
  110.         GOCT_SizeUser1, GO_TSIZE(GOM_VarSet,200,GOT_PercCharW),
  111.         GOCT_CopyUser1ToTag, GTLV_ScrollWidth,
  112.         TAG_END,
  113.         GTLV_Selected, ~0,
  114.         GTLV_Labels, NULL,
  115.         GTLV_ShowSelected, NULL,
  116.         GTLV_ScrollWidth, 16,
  117.         GT_Underscore, '_',
  118.         GA_Disabled, FALSE,
  119.         TAG_END,
  120.  
  121.         GO_GTBOX(TEXT_KIND, 0, OWNER_ID, 0,
  122.             (ULONG)&"Owner: ", PLACETEXT_LEFT|NG_HIGHLABEL),
  123.         GOCT_SizeBodyWidth, GO_TSIZE(GOM_StdAdd,500,GOT_PercCharW),
  124.         GOCT_SizeSpaceBelow, GO_TSIZE(GOM_StdSet,50,GOT_PercCharH),
  125.         TAG_END,
  126.         GTTX_Text, (ULONG)&"",
  127.         GTTX_Border, TRUE,
  128.         GA_Disabled, FALSE,
  129.         TAG_END,
  130.  
  131.         GO_VDRAWGRP(0,0,0),
  132.         GOCT_SizeSpaceAbove, GO_TSIZE(GOM_PadSet,50,GOT_PercCharH),
  133.         GOCT_SizeSpaceBelow, GO_TSIZE(GOM_PadSet,50,GOT_PercCharH),
  134.         GOCT_SizeSpaceLeft, GO_TSIZE(GOM_PadSet,50,GOT_PercCharW),
  135.         GOCT_SizeSpaceRight, GO_TSIZE(GOM_PadSet,50,GOT_PercCharW),
  136.         TAG_END,
  137.         GODT_DrawStdFrame, GO_SCLPNT(SHINEPEN,0,0,63,63),
  138.         TAG_END,
  139.  
  140.             GO_HORIZGRP(0,0,0), GOCT_EvenDistGroup, TRUE, TAG_END,
  141.     
  142.                 GO_GTBOX(BUTTON_KIND, CURSCRN_GID, CLOSE_ID, 0,
  143.                     (ULONG)&"_Close", PLACETEXT_IN),
  144.                 TAG_END,
  145.                 GA_Disabled, FALSE,
  146.                 GT_Underscore, '_',
  147.                 TAG_END,
  148.         
  149.                 GO_GTBOX(BUTTON_KIND, CURSCRN_GID, JUMPTO_ID, 0,
  150.                     (ULONG)&"_Jump to", PLACETEXT_IN),
  151.                 TAG_END,
  152.                 GA_Disabled, FALSE,
  153.                 GT_Underscore, '_',
  154.                 TAG_END,
  155.         
  156.                 GO_GTBOX(BUTTON_KIND, CURSCRN_GID, EXAMINE_ID, 0,
  157.                     (ULONG)&"_Examine", PLACETEXT_IN),
  158.                 TAG_END,
  159.                 GA_Disabled, FALSE,
  160.                 GT_Underscore, '_',
  161.                 TAG_END,
  162.     
  163.             GO_ENDGRP(),
  164.     
  165.             GO_HORIZGRP(0,0,0),
  166.             GOCT_EvenDistGroup, TRUE,
  167.             TAG_END,
  168.  
  169.                 GO_GTBOX(BUTTON_KIND, CURSCRN_GID, DUPSCRN_ID, 0,
  170.                     (ULONG)&"_Dup Scrn", PLACETEXT_IN),
  171.                 TAG_END,
  172.                 GA_Disabled, FALSE,
  173.                 GT_Underscore, '_',
  174.                 TAG_END,
  175.         
  176.                 GO_GTBOX(BUTTON_KIND, CURSCRN_GID, MODSCRN_ID, 0,
  177.                     (ULONG)&"_Mod Scrn", PLACETEXT_IN),
  178.                 TAG_END,
  179.                 GA_Disabled, FALSE,
  180.                 GT_Underscore, '_',
  181.                 TAG_END,
  182.         
  183.             GO_ENDGRP(),
  184.     
  185.             GO_HORIZGRP(0,0,0), TAG_END,
  186.  
  187.                 GO_GTBOX(BUTTON_KIND, CURSCRN_GID, MAKEDEF_ID, 0,
  188.                     (ULONG)&"De_fault", PLACETEXT_IN),
  189.                 GOCT_SizeSpaceRight, GO_TSIZE(GOM_AllSet,0,GOT_Pixels),
  190.                 TAG_END,
  191.                 GA_Disabled, FALSE,
  192.                 GT_Underscore, '_',
  193.                 TAG_END,
  194.         
  195.                 GO_GTBOX(TEXT_KIND, 0, DEFAULT_ID, 1, NULL, 0),
  196.                 GOCT_SizeBodyWidth, GO_TSIZE(GOM_StdAdd,500,GOT_PercCharW),
  197.                 GOCT_SizeSpaceLeft, GO_TSIZE(GOM_AllSet,0,GOT_Pixels),
  198.                 TAG_END,
  199.                 GTTX_Text, (ULONG)&"",
  200.                 GTTX_Border, TRUE,
  201.                 GA_Disabled, FALSE,
  202.                 TAG_END,
  203.                 
  204.             GO_ENDGRP(),
  205.  
  206.         GO_ENDGRP(),
  207.  
  208.     GO_ENDGRP(),
  209.     
  210.     GO_HORIZGRP(0,0,0), 
  211.     GOCT_EvenDistGroup, TRUE, 
  212.     GOCT_SizeSpaceAbove, GO_TSIZE(GOM_StdSet,50,GOT_PercCharH),
  213.     TAG_END,
  214.  
  215.         GO_GTBOX(CHECKBOX_KIND, 0, SHANGHAI_ID, 0,
  216.             (ULONG)&"_Shanghai", PLACETEXT_RIGHT),
  217.         TAG_END,
  218.         GTCB_Checked, FALSE,
  219.         GA_Disabled, FALSE,
  220.         GT_Underscore, '_',
  221.         TAG_END,
  222.         
  223.         GO_GTBOX(CHECKBOX_KIND, 0, AUTOPOP_ID, 0,
  224.             (ULONG)&"_AutoPop", PLACETEXT_RIGHT),
  225.         TAG_END,
  226.         GTCB_Checked, FALSE,
  227.         GA_Disabled, FALSE,
  228.         GT_Underscore, '_',
  229.         TAG_END,
  230.         
  231.     GO_ENDGRP(),
  232.     
  233.     GO_HORIZGRP(0,0,0), 
  234.     GOCT_EvenDistGroup, TRUE, 
  235.     TAG_END,
  236.  
  237.         GO_GTBOX(BUTTON_KIND, 0, NEWSCRN_ID, 0,
  238.             (ULONG)&"_New Scrn", PLACETEXT_IN),
  239.         TAG_END,
  240.         GA_Disabled, FALSE,
  241.         GT_Underscore, '_',
  242.         TAG_END,
  243.         
  244.         GO_GTBOX(BUTTON_KIND, 0, QUIT_ID, 0,
  245.             (ULONG)&"_Quit", PLACETEXT_IN),
  246.         TAG_END,
  247.         GA_Disabled, FALSE,
  248.         GT_Underscore, '_',
  249.         TAG_END,
  250.     
  251.     GO_ENDGRP(),
  252.     
  253. GO_ENDGRP(),
  254.  
  255. GO_ENDOUTLINE()
  256. };
  257.  
  258. /**
  259.  ** Handler for main window
  260.  **/
  261.  
  262. #define TEXT_LEN 252
  263.  
  264. struct main_globals {
  265.     struct List pubscrn_list;           // List of screens (struct pubscrn_entry)
  266.     struct pubscreen_entry *cur_pubscrn;    // Currently selected screen
  267.     ULONG ticks_since_update;           // How long since it's been updated
  268.  
  269.     struct List empty_list;             // Unused pubscrn_entry structures.
  270.     
  271.     struct List outline_list;           // All opened outlines.
  272.     
  273.     struct Hook bf_hook;
  274.  
  275.     UBYTE defpub_name[TEXT_LEN+4];      // Name of current default pub screen
  276. };
  277.  
  278. struct pubscreen_entry {
  279.     struct Node node;       // ln_Name points to &desc[0]
  280.     WORD resv0;
  281.     UWORD flags;            // as per PubScreenNode
  282.     WORD visitor_count;     // ""
  283.     struct Screen *screen;  // the actual screen
  284.     struct Task *owner;     // task which owns the screen
  285.     UBYTE *name;            // start of actual name in buffer
  286.     UBYTE desc[TEXT_LEN+4]; // description - 'x yy zzzzzzz...'
  287.                             // x = P if private, yy is visitor count,
  288.                             // zzz... is screen name.
  289.     UBYTE owner_name[TEXT_LEN+4];   // name of owner task.
  290. };
  291.  
  292. static void update_checkbox(struct GadOutline *go,CMDID cmdid,ULONG newval)
  293. {
  294.     ULONG oldval;
  295.     
  296.     oldval = GO_GetObjAttr(go,cmdid,0, GTCB_Checked,FALSE);
  297.     if( (!oldval && newval) || (oldval && !newval) ) {
  298.         GO_SetObjAttrs(go,cmdid,0, GTCB_Checked,newval,TAG_END);
  299.     }
  300. }
  301.  
  302. static BOOL update_publist(struct GadOutline *go)
  303. {
  304.     struct main_globals *gl;
  305.     struct PubScreenNode *cur_scrn;
  306.     struct pubscreen_entry *cur_entry;
  307.     BOOL list_changed = FALSE;
  308.     UBYTE name_selected[TEXT_LEN+4];
  309.  
  310.     if( !(gl = go->go_UserData) ) return FALSE;
  311.  
  312.     cur_entry = head_node(&gl->pubscrn_list);
  313.     name_selected[0] = 0;
  314.     
  315.     for(cur_scrn = head_node(LockPubScreenList());
  316.         cur_scrn != NULL;
  317.         cur_scrn = next_node(cur_scrn)) {
  318.         
  319.         // Check if node in list and pubscreen nodes match...
  320.         if( cur_entry == NULL || cur_entry->flags != cur_scrn->psn_Flags
  321.             || cur_entry->visitor_count != cur_scrn->psn_VisitorCount
  322.             || strcmp(cur_entry->name,cur_scrn->psn_Node.ln_Name) != 0 ) {
  323.             
  324.             // They don't; set changed flag and detach from listview because
  325.             // we are going to make changes.
  326.             if(list_changed == FALSE) {
  327.                 GO_SetObjAttrs(go,PUBLIST_ID,0,GTLV_Labels,~0,TAG_END);
  328.                 list_changed = TRUE;
  329.             }
  330.             
  331.             // If this is the currently selected screen, stash its name.
  332.             if(cur_entry && gl->cur_pubscrn == cur_entry) {
  333.                 strcpy(name_selected,gl->cur_pubscrn->name);
  334.                 gl->cur_pubscrn = NULL;
  335.             }
  336.  
  337.             // If failed because no more entries in list, get a new one.
  338.             if(cur_entry == NULL) {
  339.                 cur_entry = (struct pubscreen_entry *)RemHead(&gl->empty_list);
  340.                 if(cur_entry == NULL)
  341.                     cur_entry = AllocVec(sizeof(struct pubscreen_entry),MEMF_PUBLIC);
  342.                 if(cur_entry != NULL)
  343.                     AddTail(&gl->pubscrn_list,&cur_entry->node);
  344.             }
  345.             
  346.             // Fillin this entry.
  347.             if(cur_entry) {
  348.                 cur_entry->flags = cur_scrn->psn_Flags;
  349.                 cur_entry->visitor_count = cur_scrn->psn_VisitorCount;
  350.                 cur_entry->screen = cur_scrn->psn_Screen;
  351.                 cur_entry->owner = cur_scrn->psn_SigTask;
  352.  
  353.                 if(CheckScrnTrack(cur_scrn->psn_Screen)) {
  354.                     cur_entry->desc[0] = '*';
  355.                 } else {
  356.                     cur_entry->desc[0] = 
  357.                         ((cur_scrn->psn_Flags&PSNF_PRIVATE) ? 'P' : ' ');
  358.                 }
  359.                 cur_entry->desc[1] = (cur_scrn->psn_VisitorCount/10)+ '0';
  360.                 cur_entry->desc[2] = cur_scrn->psn_VisitorCount
  361.                                     - ((cur_entry->desc[1]-'0')*10) + '0';
  362.                 cur_entry->desc[3] = ' ';
  363.                 strncpy(&cur_entry->desc[4],cur_scrn->psn_Node.ln_Name,TEXT_LEN);
  364.                     
  365.                 cur_entry->node.ln_Name = 
  366.                     &cur_entry->desc[0];
  367.                 cur_entry->name = &cur_entry->desc[4];
  368.                 
  369.                 if(cur_scrn->psn_SigTask) {
  370.                     if(cur_scrn->psn_SigTask->tc_Node.ln_Name) {
  371.                         strncpy(&cur_entry->owner_name[0],
  372.                                 cur_scrn->psn_SigTask->tc_Node.ln_Name,TEXT_LEN);
  373.                     } else {
  374.                         strcpy(&cur_entry->owner_name[0],"Unknown.");
  375.                     }
  376.                 } else {
  377.                     strcpy(&cur_entry->owner_name[0],"None.");
  378.                 }
  379.             }
  380.         }
  381.         
  382.         // Skip to next node in listview display.
  383.         cur_entry = next_node(cur_entry);
  384.     }
  385.     UnlockPubScreenList();
  386.  
  387.     // Remove any extra entries from list.
  388.     while(cur_entry) {
  389.         struct pubscreen_entry *next_entry;
  390.  
  391.         // Set changed flag and detach from listview if needed.
  392.         if(list_changed == FALSE) {
  393.             GO_SetObjAttrs(go,PUBLIST_ID,0,GTLV_Labels,~0,TAG_END);
  394.             list_changed = TRUE;
  395.         }
  396.         
  397.         // If this is the currently selected screen, stash its name.
  398.         if(cur_entry && gl->cur_pubscrn == cur_entry) {
  399.             strcpy(name_selected,gl->cur_pubscrn->name);
  400.             gl->cur_pubscrn = NULL;
  401.         }
  402.  
  403.         next_entry = next_node(cur_entry);
  404.         Remove(&cur_entry->node);
  405.         AddHead(&gl->empty_list,&cur_entry->node);
  406.         cur_entry = next_entry;
  407.     }
  408.     
  409.     if(name_selected[0] == 0 && list_changed) {
  410.         if(go->go_Screen) {
  411.             for(cur_entry = head_node(&gl->pubscrn_list);
  412.                 cur_entry != NULL && cur_entry->screen != go->go_Screen;
  413.                 cur_entry = next_node(cur_entry))
  414.                 ;
  415.             if(cur_entry != NULL) {
  416.                 strcpy(name_selected,cur_entry->name);
  417.             }
  418.         } else {
  419.             GetDefaultPubScreen(name_selected);
  420.         }
  421.     }
  422.             
  423.     if(list_changed) {
  424.         gl->cur_pubscrn = NULL;
  425.         for(cur_entry = head_node(&gl->pubscrn_list);
  426.             gl->cur_pubscrn == NULL && cur_entry != NULL;
  427.             cur_entry = next_node(cur_entry)) {
  428.             
  429.             if(strcmp(name_selected,cur_entry->name) == 0)
  430.                 gl->cur_pubscrn = cur_entry;
  431.         }
  432.         
  433.         if(!gl->cur_pubscrn) gl->cur_pubscrn = head_node(&gl->pubscrn_list);
  434.         
  435.         GO_SetObjAttrs(go,PUBLIST_ID,0,
  436.             GTLV_Labels, &gl->pubscrn_list,
  437.             GTLV_Selected, node_to_num(&gl->pubscrn_list,gl->cur_pubscrn),
  438.             TAG_END);
  439.         GO_SetObjAttrs(go,OWNER_ID,0,
  440.             GTTX_Text, gl->cur_pubscrn ? gl->cur_pubscrn->owner_name : "",
  441.             TAG_END);
  442.     }
  443.     
  444.     // Check if default pub screen has changed
  445.     GetDefaultPubScreen(&name_selected[0]);
  446.     if(strcmp(name_selected,gl->defpub_name) != 0) {
  447.         strcpy(gl->defpub_name,name_selected);
  448.         list_changed = TRUE;
  449.         GO_SetObjAttrs(go,DEFAULT_ID,0,
  450.             GTTX_Text, gl->defpub_name,
  451.             TAG_END);
  452.     }
  453.  
  454.     {
  455.         UWORD modes;
  456.         
  457.         Forbid();
  458.         modes = SetPubScreenModes(0);
  459.         SetPubScreenModes(modes);
  460.         Permit();
  461.         
  462.         update_checkbox(go,SHANGHAI_ID,modes&SHANGHAI);
  463.         update_checkbox(go,AUTOPOP_ID,modes&POPPUBSCREEN);
  464.     }
  465.  
  466.     return list_changed;
  467. }
  468.  
  469. static void remove_outline(struct GadOutline *go,struct GadOutline *dest_go)
  470. {
  471.     struct main_globals *gl;
  472.     struct Node *cur_node;
  473.  
  474.     if(!go) return;
  475.     gl = go->go_UserData;
  476.         
  477.     if(gl) {
  478.         for(cur_node = head_node(&gl->outline_list);
  479.             cur_node != NULL;
  480.             cur_node = next_node(cur_node)) {
  481.             
  482.             if((void *)cur_node->ln_Name == (void *)dest_go) {
  483.                 Remove(cur_node);
  484.                 FreeVec(cur_node);
  485.                 cur_node = NULL;
  486.             }
  487.         }
  488.     }
  489.  
  490.     if(dest_go) ((HANDLER *)dest_go->go_UserHandler)(dest_go,
  491.                                 HNDCMD_SHUTDOWN,(struct GOIMsg *)dest_go);
  492. }
  493.  
  494. static void dist_hndcmd(struct GadOutline *go,ULONG cmd,void *msg)
  495. {
  496.     struct main_globals *gl;
  497.     struct Node *curnode;
  498.  
  499.     if(!go) return;
  500.     gl = go->go_UserData;
  501.         
  502.     if(gl) {
  503.     
  504.         // Send command to children.
  505.         for(curnode = head_node(&gl->outline_list);
  506.             curnode != NULL;
  507.             curnode = next_node(curnode)) {
  508.  
  509.             struct GadOutline *cur_go;
  510.             
  511.             cur_go = (struct GadOutline *)curnode->ln_Name;
  512.             if( ((HANDLER *)cur_go->go_UserHandler)(cur_go,cmd,msg)
  513.                     == HNDRES_CLOSEWIN ) {
  514.                 
  515.                 curnode = curnode->ln_Succ;
  516.                 remove_outline(go,cur_go);
  517.                 curnode = curnode->ln_Pred;
  518.             }
  519.         }
  520.     }
  521. }
  522.  
  523. static void hide_windows(struct GadOutline *go)
  524. {
  525.     dist_hndcmd(go,HNDCMD_HIDEWIN,NULL);
  526.     GO_CloseScreen(go);     // Make sure we totally unlink.
  527. }
  528.  
  529. static void move_windows(struct GadOutline *go)
  530. {
  531.     dist_hndcmd(go,HNDCMD_MOVEWIN,go->go_Screen);
  532. }
  533.  
  534. static void lock_program(struct GadOutline *go)
  535. {
  536.     dist_hndcmd(go,HNDCMD_LOCK,NULL);
  537.     LockGadOutline(go);
  538. }
  539.  
  540. static void unlock_program(struct GadOutline *go)
  541. {
  542.     UnlockGadOutline(go);
  543.     dist_hndcmd(go,HNDCMD_UNLOCK,NULL);
  544. }
  545.  
  546. static struct Node *add_outline(struct GadOutline *go,struct GadOutline *dest_go)
  547. {
  548.     struct main_globals *gl;
  549.     struct Node *cur_node = NULL;
  550.  
  551.     if(!go) return NULL;
  552.     if(!(gl = go->go_UserData)) return NULL;
  553.         
  554.     if(gl) {
  555.         if(!(cur_node = AllocVec(sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR))) {
  556.             return NULL;
  557.         }
  558.         
  559.         cur_node->ln_Name = (UBYTE *)dest_go;
  560.         AddTail(&gl->outline_list,cur_node);
  561.     }
  562.     return cur_node;
  563. }
  564.  
  565. static void update_curscrn(struct GadOutline *go)
  566. {
  567.     struct main_globals *gl;
  568.  
  569.     if(!go) return;
  570.     if( !(gl = go->go_UserData)) return;
  571.         
  572.     GO_SetObjAttrs(go,OWNER_ID,0,
  573.         GTTX_Text, gl->cur_pubscrn
  574.                     ? gl->cur_pubscrn->owner_name : "",
  575.         TAG_END);
  576.  
  577.     if(!gl->cur_pubscrn || (gl->cur_pubscrn->flags&PSNF_PRIVATE)) {
  578.         GO_SetObjGrpAttrs(go,GO_CMDID(CURSCRN_GID,0),0,
  579.             GA_Disabled,TRUE,TAG_END);
  580.     } else {
  581.         GO_SetObjGrpAttrs(go,GO_CMDID(CURSCRN_GID,0),0,
  582.             GA_Disabled,FALSE,TAG_END);
  583.         if(gl->cur_pubscrn->flags&PSNF_PRIVATE) {
  584.             GO_SetObjAttrs(go,JUMPTO_ID,0,GA_Disabled,TRUE,TAG_END);
  585.         } else {
  586.             GO_SetObjAttrs(go,JUMPTO_ID,0,GA_Disabled,FALSE,TAG_END);
  587.         }
  588.         if( gl->cur_pubscrn->visitor_count > 0
  589.             && !(gl->cur_pubscrn->screen == go->go_Screen
  590.                  && gl->cur_pubscrn->visitor_count <= 2) ) {
  591.             GO_SetObjAttrs(go,CLOSE_ID,0,GA_Disabled,TRUE,TAG_END);
  592.             GO_SetObjAttrs(go,MODSCRN_ID,0,GA_Disabled,TRUE,TAG_END);
  593.         } else {
  594.             GO_SetObjAttrs(go,CLOSE_ID,0,GA_Disabled,FALSE,TAG_END);
  595.             GO_SetObjAttrs(go,MODSCRN_ID,0,GA_Disabled,FALSE,TAG_END);
  596.         }
  597.     }
  598. }
  599.  
  600. static ULONG __saveds __interrupt
  601. main_handler(struct GadOutline *go, ULONG command, struct GOIMsg *msg)
  602. {
  603.     struct main_globals *gl;
  604.     struct Gadget *gadget;
  605.     ULONG class;
  606.     UWORD code;
  607.     UWORD qual;
  608.  
  609.     if(go == NULL) return HNDRES_TERMINATE;
  610.  
  611.     if( !(gl = (struct main_globals *)go->go_UserData) ) {
  612.         DestroyMain(go);
  613.         return HNDRES_TERMINATE;
  614.     }
  615.  
  616.     if(command == HNDCMD_IDCMPMSG) {
  617.         if( msg ) {
  618.             class = msg->StdIMsg.Class;
  619.             code = msg->StdIMsg.Code;
  620.             qual = msg->StdIMsg.Qualifier;
  621.             gadget = (struct Gadget *)msg->StdIMsg.IAddress;
  622.         } else {
  623.             return HNDRES_TERMINATE;
  624.         }
  625.     } else if(command == HNDCMD_SHUTDOWN) {
  626.         if(msg && go != (struct GadOutline *)msg) {
  627.             remove_outline(go,(struct GadOutline *)msg);
  628.             update_curscrn(go);
  629.             return HNDRES_NORMAL;
  630.         } else {
  631.             return HNDRES_TERMINATE;
  632.         }
  633.     } else if(command == HNDCMD_TICK) {
  634.         dist_hndcmd(go,command,msg);
  635.         class = IDCMP_INTUITICKS;
  636.     } else {
  637.         return HNDRES_NORMAL;
  638.     }
  639.  
  640.     switch (class) {
  641.  
  642.         case IDCMP_CLOSEWINDOW:
  643.         {
  644.             return HNDRES_TERMINATE;
  645.         } break;
  646.  
  647.         case IDCMP_REFRESHWINDOW:
  648.         {
  649.             GO_BeginRefresh(go);
  650.             GO_EndRefresh(go, TRUE);
  651.         } break;
  652.  
  653.         case IDCMP_INTUITICKS:
  654.         {
  655.             if( (++gl->ticks_since_update) > 5) {
  656.                 if(update_publist(go)) update_curscrn(go);
  657.                 gl->ticks_since_update = 0;
  658.             }
  659.         } break;
  660.  
  661.         case IDCMP_MENUPICK:
  662.         {
  663.             struct MenuItem *item;
  664.             while(code != MENUNULL) {
  665.                 item = ItemAddress(go->go_MenuStrip, code);
  666.  
  667.                 switch((ULONG)GTMENUITEM_USERDATA(item)) {
  668.                 
  669.                     case QUIT_ID:
  670.                     {
  671.                         return HNDRES_TERMINATE;
  672.                     } break;
  673.                     
  674.                     case ABOUT_ID:
  675.                     {
  676.                         lock_program(go);
  677.                         GO_ShowError(go,GO_MAKEERR(GOTYPE_FINE,0),NULL,
  678. "%ls v%ls\nCopyright © %ls Dianne Hackborn\nCreated on %ls at %ls\n\n"
  679. "User interface created with\n^Zb v^Zv.^Zr\n\n"
  680. "This program is shareware.  If you find\n"
  681. "it useful, please send $5 or whatever you\n"
  682. "feel it is worth to:\n"
  683. "    Dianne Hackborn\n"
  684. "    2895 Los Altos Drive\n"
  685. "    Meridian, ID 83642",
  686.                             &__ProgName[0],&__FullVersion[0],&__BuildYear[0],&__BuildDate[0],&__BuildTime[0]);
  687.                         unlock_program(go);
  688.                     } break;
  689.                 }
  690.  
  691.                 code = item->NextSelect;
  692.             }
  693.         } break;
  694.  
  695.         case IDCMP_GADGETUP:
  696.         case IDCMP_GADGETDOWN:
  697.         {
  698.         
  699.             switch(gadget->GadgetID) {
  700.             
  701.                 case PUBLIST_ID:
  702.                 {
  703.                     gl->cur_pubscrn = num_to_node(&gl->pubscrn_list,code);
  704.                     update_curscrn(go);
  705.                 } break;
  706.  
  707.                 case CLOSE_ID:
  708.                 {
  709.                     struct Screen *scrn;
  710.  
  711.                     if(gl->cur_pubscrn) {
  712.                         BOOL do_reopen = FALSE;
  713.     
  714.                         scrn = LockPubScreen(gl->cur_pubscrn->name);
  715.                         if(scrn == go->go_Screen) {
  716.                             do_reopen = TRUE;
  717.                             hide_windows(go);
  718.                             GO_CloseScreen(go);     // Make sure we totally unlink
  719.                         }
  720.  
  721.                         Forbid();
  722.                         UnlockPubScreen(NULL,scrn);
  723.                         (void)CloseScrnTrack(scrn);
  724.                         Permit();
  725.                         if(do_reopen) {
  726.                             GO_OpenWindow(go,
  727.                                     WA_PubScreenName, gl->cur_pubscrn->name,
  728.                                     TAG_END);
  729.                             move_windows(go);
  730.                         }
  731.                         gl->cur_pubscrn = NULL;
  732.                     }
  733.                     if(update_publist(go)) update_curscrn(go);
  734.                 } break;
  735.  
  736.                 case JUMPTO_ID:
  737.                 {
  738.                     hide_windows(go);
  739.                     DimenGadOutline(go,
  740.                         GOA_ScreenName,
  741.                             gl->cur_pubscrn ? gl->cur_pubscrn->name : "",
  742.                         GOA_ScreenFallBack, TRUE,
  743.                         TAG_END);
  744.                     if(go->go_LastReqReturn)
  745.                         DimenGadOutline(go,GOA_ScreenAddr,NULL,TAG_END);
  746.                         if(go->go_LastReqReturn)
  747.                             DimenGadOutline(go,GOA_ScreenName,"Workbench",TAG_END);
  748.                             if(go->go_LastReqReturn)
  749.                                 return HNDRES_TERMINATE;
  750.  
  751.                     move_windows(go);
  752.                     if(!GO_OpenWindow(go,TAG_END)) return HNDRES_TERMINATE;
  753.                     update_publist(go);
  754.                     update_curscrn(go);
  755.                 } break;
  756.  
  757.                 case EXAMINE_ID:
  758.                 {
  759.                     struct GadOutline *ex_go;
  760.                     struct Screen *scrn;
  761.                     
  762.                     if(!gl->cur_pubscrn)
  763.                         return HNDRES_NORMAL;
  764.                     if(!(scrn=LockPubScreen(gl->cur_pubscrn->name)))
  765.                         return HNDRES_NORMAL;
  766.  
  767.                     if(ex_go=CreateExamine(go,gl->cur_pubscrn->name,scrn)) {
  768.                         if(!add_outline(go,ex_go)) {
  769.                             ((HANDLER *)ex_go->go_UserHandler)(ex_go,
  770.                                         HNDCMD_SHUTDOWN,(struct GOIMsg *)ex_go);
  771.                         }
  772.                     }
  773.                     UnlockPubScreen(NULL,scrn);
  774.                     if(update_publist(go)) update_curscrn(go);
  775.                         
  776.                 } break;
  777.  
  778.                 case MAKEDEF_ID:
  779.                 {
  780.                     if(gl->cur_pubscrn) {
  781.                         SetDefaultPubScreen(gl->cur_pubscrn->name);
  782.                         update_publist(go);
  783.                         update_curscrn(go);
  784.                     }
  785.                 } break;
  786.  
  787.                 case DUPSCRN_ID:
  788.                 {
  789.                     struct GadOutline *ns_go;
  790.                     struct Screen *scrn;
  791.                     
  792.                     if(!gl->cur_pubscrn)
  793.                         return HNDRES_NORMAL;
  794.                     if(!(scrn=LockPubScreen(gl->cur_pubscrn->name)))
  795.                         return HNDRES_NORMAL;
  796.  
  797.                     if(ns_go=CreateNewScrn(go,gl->cur_pubscrn->name,scrn,FALSE)) {
  798.                         if(!add_outline(go,ns_go)) {
  799.                             ((HANDLER *)ns_go->go_UserHandler)(ns_go,
  800.                                         HNDCMD_SHUTDOWN,(struct GOIMsg *)ns_go);
  801.                         }
  802.                     }
  803.                     UnlockPubScreen(NULL,scrn);
  804.                     if(update_publist(go)) update_curscrn(go);
  805.                         
  806.                 } break;
  807.  
  808.                 case MODSCRN_ID:
  809.                 {
  810.                     struct GadOutline *ns_go;
  811.                     struct Screen *scrn;
  812.                     
  813.                     if(!gl->cur_pubscrn)
  814.                         return HNDRES_NORMAL;
  815.                     if(!(scrn=LockPubScreen(gl->cur_pubscrn->name)))
  816.                         return HNDRES_NORMAL;
  817.  
  818.                     if(ns_go=CreateNewScrn(go,gl->cur_pubscrn->name,scrn,TRUE)) {
  819.                         if(!add_outline(go,ns_go)) {
  820.                             ((HANDLER *)ns_go->go_UserHandler)(ns_go,
  821.                                         HNDCMD_SHUTDOWN,(struct GOIMsg *)ns_go);
  822.                         }
  823.                     }
  824.                     UnlockPubScreen(NULL,scrn);
  825.                     if(update_publist(go)) update_curscrn(go);
  826.                         
  827.                 } break;
  828.  
  829.                 case SHANGHAI_ID:
  830.                 {
  831.                     ULONG newval;
  832.                     UWORD modes;
  833.                     
  834.                     newval = GO_GetObjAttr(go,SHANGHAI_ID,0, GTCB_Checked,FALSE);
  835.                     Forbid();
  836.                     modes = SetPubScreenModes(0);
  837.                     SetPubScreenModes(
  838.                         (modes&~(SHANGHAI)) | (newval ? SHANGHAI : 0) );
  839.                     Permit();
  840.                 } break;
  841.  
  842.                 case AUTOPOP_ID:
  843.                 {
  844.                     ULONG newval;
  845.                     UWORD modes;
  846.                     
  847.                     newval = GO_GetObjAttr(go,AUTOPOP_ID,0, GTCB_Checked,FALSE);
  848.                     Forbid();
  849.                     modes = SetPubScreenModes(0);
  850.                     SetPubScreenModes(
  851.                         (modes&~(POPPUBSCREEN)) | (newval ? POPPUBSCREEN : 0) );
  852.                     Permit();
  853.                 } break;
  854.  
  855.                 case NEWSCRN_ID:
  856.                 {
  857.                     struct GadOutline *ns_go;
  858.                     struct Screen *scrn;
  859.                     
  860.                     if(!(scrn=LockPubScreen(NULL)))
  861.                         return HNDRES_NORMAL;
  862.  
  863.                     if(ns_go=CreateNewScrn(go,NULL,scrn,FALSE)) {
  864.                         if(!add_outline(go,ns_go)) {
  865.                             ((HANDLER *)ns_go->go_UserHandler)(ns_go,
  866.                                         HNDCMD_SHUTDOWN,(struct GOIMsg *)ns_go);
  867.                         }
  868.                     }
  869.                     UnlockPubScreen(NULL,scrn);
  870.                     if(update_publist(go)) update_curscrn(go);
  871.                         
  872.                 } break;
  873.  
  874.                 case QUIT_ID:
  875.                 {
  876.                     return HNDRES_TERMINATE;
  877.                 } break;
  878.             }
  879.         } break;
  880.     }
  881.     
  882.     return HNDRES_NORMAL;
  883. }
  884.  
  885. void DestroyMain(struct GadOutline *go)
  886. {
  887.     struct main_globals *gl;
  888.     struct Node *curnode;
  889.  
  890.     if(!go) return;
  891.     gl = go->go_UserData;
  892.         
  893.     GO_SetObjAttrs(go,PUBLIST_ID,0,GTLV_Labels,0,TAG_END);
  894.  
  895.     if(gl) {
  896.     
  897.         // Close all opened outlines.
  898.         while( (curnode = RemTail(&gl->outline_list)) != NULL ) {
  899.             struct GadOutline *cur_go;
  900.             
  901.             cur_go = (struct GadOutline *)curnode->ln_Name;
  902.             ((HANDLER *)cur_go->go_UserHandler)(cur_go,
  903.                     HNDCMD_SHUTDOWN,(struct GOIMsg *)cur_go);
  904.             FreeVec(curnode);
  905.         }
  906.         
  907.         // Free list of public screens.
  908.         while( (curnode = RemTail(&gl->pubscrn_list)) != NULL ) {
  909.             FreeVec(curnode);
  910.         }
  911.         
  912.         // Free extra list of public screen nodes.
  913.         while( (curnode = RemTail(&gl->empty_list)) != NULL ) {
  914.             FreeVec(curnode);
  915.         }
  916.     }
  917.     
  918.     FreeGadOutline(go);
  919.     
  920.     // Free global variables.
  921.     if(gl) FreeVec(gl);
  922. }
  923.  
  924. struct GadOutline *CreateMain(struct MsgPort *glob_port)
  925. {
  926.     struct GadOutline *go;
  927.     struct main_globals *gl;
  928.     
  929.     go = AllocGadOutline(&main_outline[0],
  930.             GOA_OutlineSize,    sizeof(main_outline),
  931.             //GOA_UserIDCMP,        glob_port,
  932.             TAG_END);
  933.     if(!go) return NULL;
  934.     
  935.     gl = AllocVec(sizeof(struct main_globals),MEMF_PUBLIC|MEMF_CLEAR);
  936.     if(!gl) {
  937.         DestroyMain(go);
  938.         return NULL;
  939.     }
  940.     
  941.     NewList(&gl->pubscrn_list);
  942.     NewList(&gl->empty_list);
  943.     NewList(&gl->outline_list);
  944.     go->go_UserData = gl;
  945.     SetupBackFillHook(&gl->bf_hook,go);
  946.     GO_SetObjAttrs(go,WINTAGS_ID,0,WA_BackFill,&gl->bf_hook,TAG_END);
  947.  
  948.     update_publist(go);
  949.     update_curscrn(go);
  950.  
  951.     if( !GO_OpenWindow(go, WA_PubScreen, NULL, TAG_END) ) {
  952.         if( !GO_OpenWindow(go, WA_PubScreenName, "Workbench", TAG_END) ) {
  953.             DestroyMain(go);
  954.             return NULL;
  955.         }
  956.     }
  957.     
  958.     return go;
  959. }
  960.  
  961. static void pnum32(UBYTE *to,ULONG num,ULONG bitsperdig,ULONG numdig,ULONG space)
  962. {
  963.     if(space == 0) space = 2000;
  964.     
  965.     while(numdig > 0) {
  966.         UBYTE curdig;
  967.         
  968.         curdig = (num>>((numdig-1)*bitsperdig)) & ((1<<bitsperdig)-1);
  969.         if(curdig < 10) *to = curdig + '0';
  970.         else *to = curdig + 'A' - 10;
  971.         to++;
  972.         numdig--;
  973.         if(numdig > 0 && (numdig%space) == 0) {
  974.             *to = '.';
  975.             to++;
  976.         }
  977.     }
  978.     *to = 0;
  979. }
  980.  
  981. #define phex32(to,num,numdig,space) pnum32(to,num,4,numdig,space)
  982. #define pbin32(to,num,numdig,space) pnum32(to,num,1,numdig,space)
  983.  
  984. static void read_modes(struct GadOutline *go,struct List *modelist)
  985. {
  986.     ULONG mode;
  987.  
  988.     NewList(modelist);
  989.  
  990.     // Get display modes.
  991.     mode = INVALID_ID;
  992.  
  993.     while( (mode = NextDisplayInfo(mode)) != INVALID_ID ) {
  994.         struct ModeEntry *entry;
  995.         struct NameInfo info;
  996.  
  997.         if( ModeNotAvailable(mode) == 0
  998.             && GetDisplayInfoData(NULL,(UBYTE *)&info,sizeof(info),
  999.                 DTAG_NAME,mode) ) {
  1000.  
  1001.             if(entry = GO_AllocMem(go,GOTYPE_WARN,
  1002.                             sizeof(struct ModeEntry),MEMF_PUBLIC|MEMF_CLEAR)) {
  1003.                 entry->mode = mode;
  1004.                 GetDisplayInfoData(NULL,(UBYTE *)&entry->disp,
  1005.                                     sizeof(entry->disp),DTAG_DISP,mode);
  1006.                 GetDisplayInfoData(NULL,(UBYTE *)&entry->dims,
  1007.                                     sizeof(entry->dims),DTAG_DIMS,mode);
  1008.                 GetDisplayInfoData(NULL,(UBYTE *)&entry->mntr,
  1009.                                     sizeof(entry->mntr),DTAG_MNTR,mode);
  1010.                 entry->name = info;
  1011.                 if(entry->name.Name[0] == 0) {
  1012.                     entry->name.Name[0] = '0';
  1013.                     entry->name.Name[1] = 'x';
  1014.                     phex32(&entry->name.Name[2],mode,8,0);
  1015.                 }
  1016.                 entry->node.ln_Name = &entry->name.Name[0];
  1017.                 AddTail(modelist,&entry->node);
  1018.             }
  1019.  
  1020.         }
  1021.     }
  1022. }
  1023.     
  1024. void delete_timer(struct timerequest *tr)
  1025. {
  1026.     struct MsgPort *tp;
  1027.  
  1028.     if (tr != 0 ) {
  1029.         tp = tr->tr_node.io_Message.mn_ReplyPort;
  1030.  
  1031.         if (tp != 0) {
  1032.             DeletePort(tp);
  1033.         }
  1034.  
  1035.         CloseDevice( (struct IORequest *) tr );
  1036.         DeleteExtIO( (struct IORequest *) tr );
  1037.     }
  1038. }
  1039.  
  1040. struct timerequest *create_timer( ULONG unit )
  1041. {
  1042.     LONG error;
  1043.     struct MsgPort *timerport;
  1044.     struct timerequest *TimerIO;
  1045.  
  1046.     timerport = CreatePort( 0, 0 );
  1047.     if (timerport == NULL )
  1048.         return( NULL );
  1049.  
  1050.     TimerIO = (struct timerequest *)
  1051.         CreateExtIO( timerport, sizeof( struct timerequest ) );
  1052.     if (TimerIO == NULL ) {
  1053.         DeletePort(timerport);   /* Delete message port */
  1054.         return( NULL );
  1055.     }
  1056.  
  1057.     error = OpenDevice( TIMERNAME, unit,(struct IORequest *) TimerIO, 0L );
  1058.     if (error != 0 ) {
  1059.         delete_timer( TimerIO );
  1060.         return( NULL );
  1061.     }
  1062.     return( TimerIO );
  1063. }
  1064.  
  1065. void abort_timer(struct timerequest *tr)
  1066. {
  1067.     AbortIO((struct IORequest *)tr);
  1068.     WaitIO((struct IORequest *)tr);
  1069. }
  1070.  
  1071. void send_timer(struct timerequest *tr)
  1072. {
  1073.     tr->tr_time.tv_secs = 1;
  1074.     tr->tr_time.tv_micro = 0;
  1075.     tr->tr_node.io_Command = TR_ADDREQUEST;
  1076.     SendIO((struct IORequest *)tr);
  1077. }
  1078.  
  1079. #ifdef BETALIB
  1080. struct Library *GadOutlineBase = NULL;
  1081. #endif
  1082.  
  1083. void __regargs main(int argc,char **argv)
  1084. {
  1085.     struct Process *me = NULL;
  1086.     struct Window *oldwin = NULL;   // what me->pr_WindowPtr previously was
  1087.     struct timerequest *timer;
  1088.     struct GadOutline *main_go;
  1089.  
  1090.     if( !(me = (struct Process *)FindTask(NULL)) ) {
  1091.         exit(20);
  1092.     }
  1093.     oldwin = (struct Window *)me->pr_WindowPtr;
  1094.  
  1095.     timer = create_timer(UNIT_VBLANK);
  1096.     if(!timer) exit(20);
  1097.  
  1098.     #ifdef BETALIB
  1099.     if( !(GadOutlineBase = OpenLibrary("beta_gadoutline.library",1)) ) {
  1100.         delete_timer(timer);
  1101.         exit(20);
  1102.     }
  1103.     #endif
  1104.     
  1105.     main_go = CreateMain(NULL);
  1106.     if(!main_go) {
  1107.         #ifdef BETALIB
  1108.         CloseLibrary(GadOutlineBase);
  1109.         #endif
  1110.         delete_timer(timer);
  1111.         exit(20);
  1112.     }
  1113.     
  1114.     read_modes(main_go,&ScreenModeList);
  1115.  
  1116.     send_timer(timer);  // Prime the pump... ;)
  1117.  
  1118.     while(1) {
  1119.         struct GadOutline *msg_go;
  1120.         struct GOIMsg *msg;
  1121.         ULONG ret = HNDRES_NORMAL;
  1122.  
  1123.         me->pr_WindowPtr = (APTR)main_go->go_Window;
  1124.         
  1125.         Wait( (1L<<main_go->go_MsgPort->mp_SigBit) 
  1126.               | (1L<<timer->tr_node.io_Message.mn_ReplyPort->mp_SigBit) );
  1127.  
  1128.         while( (msg = GO_GetGOIMsg(main_go)) ) {
  1129.             struct GOIMsg *dup_msg;
  1130.             
  1131.             msg_go = GO_GetGOFromGOIMsg(msg);
  1132.             
  1133.             if(msg_go)
  1134.                 dup_msg = GO_DupGOIMsg(msg_go,msg);
  1135.             else
  1136.                 dup_msg = NULL;
  1137.  
  1138.             GO_ReplyGOIMsg(msg);
  1139.             
  1140.             if(dup_msg) {
  1141.                 ret = ((HANDLER *)msg_go->go_UserHandler)
  1142.                     (msg_go,HNDCMD_IDCMPMSG,dup_msg);
  1143.                 (void)GO_UndupGOIMsg(dup_msg);
  1144.             }
  1145.             
  1146.             if(ret == HNDRES_CLOSEWIN) {
  1147.                 ret = ((HANDLER *)main_go->go_UserHandler)
  1148.                     (main_go,HNDCMD_SHUTDOWN,(struct GOIMsg *)msg_go);
  1149.             }
  1150.             if(ret == HNDRES_TERMINATE) {
  1151.                 D(bug("Quiting..."));
  1152.                 DestroyMain(main_go);
  1153.                 #ifdef BETALIB
  1154.                 CloseLibrary(GadOutlineBase);
  1155.                 #endif
  1156.                 D(bug(" GadOutline..."));
  1157.                 abort_timer(timer);
  1158.                 D(bug(" Timer Request..."));
  1159.                 delete_timer(timer);
  1160.                 D(bug(" Timer Device.  Done.\n"));
  1161.                 me->pr_WindowPtr = (APTR)oldwin;
  1162.                 exit(0);
  1163.             }
  1164.         }
  1165.  
  1166.         if( GetMsg(timer->tr_node.io_Message.mn_ReplyPort) ) {
  1167.             send_timer(timer);
  1168.             ((HANDLER *)main_go->go_UserHandler)(main_go,HNDCMD_TICK,NULL);
  1169.         }
  1170.     }
  1171. }
  1172.